//  Copyright (c) 2009 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using DNA.Mvc.jQuery;
using System.Globalization;
using System.Collections;
using System.IO;
using System.Web.Configuration;
using System.Resources;
using DNA.IO.Compress;
using System.Net.Configuration;
using DNA.Mvc.Management;
using System.Xml;
using System.Net.Mail;
using DNA.Mvc.UI;

namespace DNA.Mvc.Controllers
{
    /// <summary>
    /// Provides the actions of the system settings of the website.
    /// </summary>
    public class SysController : Controller
    {
        private WebSiteContext _context;
        public SysController(WebSiteContext context) { _context = context; }


        [MyControlPanel(ResKey = "Sys_SiteStat",ShowInPersonalSiteOnly=true)]
        [SiteControlPanel(ResKey = "Sys_SiteStat")]
        [SecurityAction("Management base", "Control panel", "Allows users can acces the control panel",
            TitleResName = "SA_ControlPanel",
            DescResName = "SA_ControlPanelDesc",
            PermssionSetResName = "SA_Managementbase"
            )]
        public ActionResult Index()
        {
            if (_context.Web == null)
            {
                if (_context.EnablePersonalWeb)
                    return RedirectToAction("SetupMysite", "Solution", new { Area = "", website = "home" });
                else
                    return new WebsiteNotFoundResult();
            }
            else
            {
                if (!_context.Web.IsRoot)
                {
                    if (_context.EnablePersonalWeb)
                    {
                        var website = HttpContext.Request.RequestContext.RouteData.Values["website"] as string;
                        if ((!string.IsNullOrEmpty(website) && (website.Equals(User.Identity.Name, StringComparison.OrdinalIgnoreCase))))
                        {
                            if (_context.DataContext.Webs.GetByName(website) == null)
                                return RedirectToAction("SetupMysite", "Solution", new { Area = "", website = "home" });
                        }
                    }
                }
            }
            return View();
        }

        [SecurityAction("Management base", "Edit robot.txt", "Allows users can edit the robot.txt file.",
            TitleResName = "SA_Robot",
            DescResName = "SA_RobotDesc",
            PermssionSetResName = "SA_Managementbase"
            )]
        [SiteControlPanel(Text = "robots.txt", Group = "Tools", GroupResKey = "RES_TOOLS", ShowInTopSiteOnly = true)]
        public ActionResult Robot()
        {
            ViewBag.Rules = "";
            ViewBag.Error = "";
            var robot = Server.MapPath("~/robots.txt");
            try
            {
                if (!System.IO.File.Exists(robot))
                {
                    System.IO.File.CreateText(robot);
                }
                else
                {
                    using (var reader = System.IO.File.OpenText(robot))
                    {
                        ViewBag.Rules = reader.ReadToEnd();
                    }
                }
            }
            catch (Exception e)
            {
                ViewBag.Error = e.Message;
                return View();
            }
            return View();
        }

        [Authorize, HttpPost]
        public ActionResult Robot(string rules)
        {
            if (_context.IsAuthorized(this, "Robot"))
            {
                ViewBag.Rules = rules;
                ViewBag.Error = "";
                var robot = Server.MapPath("~/robots.txt");
                try
                {
                    using (var writer = new System.IO.StreamWriter(robot))
                    {
                        writer.Write(rules);
                        writer.Flush();
                    }
                }
                catch (Exception e)
                {
                    ViewBag.Error = e.Message;
                    return View();
                }
                return View();
            }
            else
            {
                return RedirectToAction("AccessDenied", "Security", new { Area = "" });
            }
        }

        [SiteControlPanel(ResKey = "RES_METATAGS", Group = "Tools", ShowInTopSiteOnly = true)]
        public ActionResult Metas()
        {
            string fileName = Server.MapPath("~/content/templates/metas.cshtml");
            if (System.IO.File.Exists(fileName))
            {
                ViewBag.Metas = System.IO.File.ReadAllText(fileName);
            }
            else
                ViewBag.Metas = "";
            return View();
        }

        [HttpPost, ValidateAntiForgeryToken, ValidateInput(false), Authorize]
        public ActionResult Metas(string metas)
        {
            string fileName = Server.MapPath("~/content/templates/metas.cshtml");
            if (!string.IsNullOrEmpty(metas))
                System.IO.File.WriteAllText(fileName, metas);
            else
            {
                if (System.IO.File.Exists(fileName))
                    System.IO.File.Delete(fileName);
            }

            return RedirectToAction("Metas");
        }

        [MyControlPanel(ResKey = "RES_WEB_SETTING", Sequence = 0, ShowInPersonalSiteOnly = true)]
        [SiteControlPanel(ResKey = "RES_WEB_SETTING", Sequence = 0)]
        [SecurityAction("Management base", "Manage site settings", "Allows users can view the common site settings.",
            TitleResName = "SA_ManageSiteSettings",
            DescResName = "SA_ManageSiteSettingsDesc",
            PermssionSetResName = "SA_Managementbase"
            )]
        public ActionResult SiteSettings()
        {
            ViewData.Model = _context.Web;
            //if (!_context.Web.IsRoot)
            //    this.CurrentWeb().EnsurePersonalWebFiles();
            return View();
        }

        [Authorize, HttpPost, ValidateInput(false), MyControlPanel, SiteControlPanel]
        public ActionResult SiteSettings(FormCollection forms)
        {
            if (_context.IsAuthorized(this, "SiteSettings"))
            {
                var web = _context.Web;
                if (TryUpdateModel<Web>(web, "Web"))
                {
                    TryUpdateModel<WebMasterTools>(web.MasterTools, "MasterTools");
                    _context.DataContext.Webs.Update(web);
                    _context.DataContext.SaveChanges();
                }

                if (web.IsRoot)
                {
                    if (forms.AllKeys.Contains("EnableSNS"))
                    {
                        var enableSNS = bool.Parse(forms["EnableSNS"]);
                        if (enableSNS != _context.EnablePersonalWeb)
                            DnaConfig.UpdateWebConfig("configuration/appSettings/add[@key='enablePersonalWeb']", "value", enableSNS.ToString().ToLower());
                    }

                    if (forms.AllKeys.Contains("FacebookAppID"))
                        DnaConfig.UpdateWebConfig("configuration/appSettings/add[@key='facebookAppID']", "value", forms["FacebookAppID"]);

                    if (forms.AllKeys.Contains("FacebookSecret"))
                        DnaConfig.UpdateWebConfig("configuration/appSettings/add[@key='facebookSecret']", "value", forms["FacebookSecret"]);

                    if (forms.AllKeys.Contains("TwitterConsumerKey"))
                        DnaConfig.UpdateWebConfig("configuration/appSettings/add[@key='twitterConsumerKey']", "value", forms["TwitterConsumerKey"]);

                    if (forms.AllKeys.Contains("TwitterConsumerSecret"))
                        DnaConfig.UpdateWebConfig("configuration/appSettings/add[@key='twitterConsumerSecret']", "value", forms["TwitterConsumerSecret"]);
                }
                return View(web);
            }
            else
            {
                return new HttpUnauthorizedResult();
                //return RedirectToAction("AccessDenied", "Security", new { Area = "" });
            }
        }

        [SiteControlPanel(ResKey = "RES_SMTPSETTINGS", ShowInTopSiteOnly = true)]
        [SecurityAction("Management base", "Smtp settings", "Allows users can change the SMTP settings.",
              PermssionSetResName = "SA_Managementbase",
            TitleResName = "SA_SMTPSettings",
            DescResName = "SA_SMTPSettingsDesc"
            )]
        public ActionResult Smtp()
        {
            var netConfig = WebConfigurationManager.OpenWebConfiguration("~/net.config");
            var healthConfig = WebConfigurationManager.OpenWebConfiguration("~/health.config");
            var section = netConfig.GetSection("system.net/mailSettings/smtp") as SmtpSection;
            var health = healthConfig.GetSection("system.web/healthMonitoring") as HealthMonitoringSection;
            var criticalProvider = health.Providers["CriticalMailEventProvider"];

            if (section != null)
            {
                var network = section.Network;
                var smtpModel = new SmtpModel()
                {
                    From = section.From,
                    DefaultCredentials = network.DefaultCredentials,
                    EnableSsl = network.EnableSsl,
                    Host = network.Host,
                    Password = network.Password,
                    UserName = network.UserName,
                    Port = network.Port,
                    CriticalMail = criticalProvider.Parameters["to"]
                };

                return View(smtpModel);
            }

            return View();
        }

        [HttpPost]
        public ActionResult Smtp([Bind(Prefix = "SmtpModel")] SmtpModel smtp)
        {
            var xmlDoc = new XmlDocument();
            var filename = HttpContext.Server.MapPath("~/net.config");
            xmlDoc.Load(filename);
            xmlDoc.DocumentElement.Attributes["from"].Value = smtp.From;
            var network = xmlDoc.DocumentElement.SelectSingleNode("network");
            network.Attributes["port"].Value = smtp.Port.ToString();
            network.Attributes["userName"].Value = smtp.UserName;
            network.Attributes["password"].Value = smtp.Password;
            network.Attributes["host"].Value = smtp.Host;
            network.Attributes["enableSsl"].Value = smtp.EnableSsl.ToString().ToLower();
            network.Attributes["defaultCredentials"].Value = smtp.DefaultCredentials.ToString().ToLower();
            xmlDoc.Save(filename);

            filename = HttpContext.Server.MapPath("~/health.config");
            xmlDoc.Load(filename);
            var criticalProvider = xmlDoc.DocumentElement.SelectSingleNode("providers/add[@name='CriticalMailEventProvider']");
            criticalProvider.Attributes["from"].Value = string.IsNullOrEmpty(smtp.From) ? "from@domain.com" : smtp.From;
            criticalProvider.Attributes["to"].Value = smtp.CriticalMail;
            xmlDoc.Save(filename);
            return View(smtp);
        }

        public bool TestSmtp()
        {
            var smtpClient = new SmtpClient();
            var testMessage = new MailMessage();
            var healthConfig = WebConfigurationManager.OpenWebConfiguration("~/health.config");
            var health = healthConfig.GetSection("system.web/healthMonitoring") as HealthMonitoringSection;
            var criticalProvider = health.Providers["CriticalMailEventProvider"];
            var to = criticalProvider.Parameters["to"];
            var from = criticalProvider.Parameters["from"];
            var msg = new MailMessage()
            {
                Body = "This is a tesing mail."
            };

            msg.From = new MailAddress(from);
            msg.To.Add(to);
            msg.Subject = "Smtp testing";

            try
            {
                smtpClient.Send(msg);
                return true;
            }
            catch
            {
                return false;
            }
        }

        [SecurityAction("Theming", "Change icon and logo", "Allows users can change the website title and logo.",
            TitleResName = "SA_ChangeIconAndLogo",
            DescResName = "SA_ChangeIconAndLogoDesc",
            PermssionSetResName = "SA_Theming")]
        [MyControlPanel(ResKey = "RES_SITE_LOGOANDICON", Sequence = 2, ShowInPersonalSiteOnly = true, Group = "Appearance", GroupResKey = "RES_APPEARANCE_SETTINGS")]
        [SiteControlPanel(ResKey = "RES_SITE_LOGOANDICON", Sequence = 2, Group = "Appearance", GroupResKey = "RES_APPEARANCE_SETTINGS")]
        public ActionResult SiteLogo()
        {
            return View(_context.Web);
        }

        [Authorize, HttpPost, MyControlPanel,SiteControlPanel]
        public ActionResult SiteLogo(FormCollection forms)
        {
            var web = _context.Web;
            if (TryUpdateModel<Web>(web, "Web"))
            {
                _context.DataContext.Webs.Update(web);
                _context.DataContext.SaveChanges();
            }
            return View(web);
        }

        /// <summary>
        /// Change the current language for the current user.
        /// </summary>
        /// <param name="lang">The specified Language ID</param>
        /// <returns></returns>
        public ActionResult ChangeLanguage(string lang)
        {
            if (lang == null)
                return View("Home");
            else
            {
                //if (Request.IsAuthenticated)
                //{
                //    if (HttpContext.Profile["Language"] != null)
                //        HttpContext.Profile["Language"] = lang;
                //}
                GE.SetLanguageCookie(HttpContext, "userLanguage", lang);
                if (!string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]))
                    return Redirect(Server.UrlDecode(Request.QueryString["ReturnUrl"]));
                else
                    return Redirect("/");
            }
        }

        ///// <summary>
        ///// Change the current theme of the website.
        ///// </summary>
        ///// <param name="theme"></param>
        ///// <returns></returns>
        //[AcceptVerbs(HttpVerbs.Post)]
        //[SecurityAction("Management base", "Change theme", "Allows users can chage themes.",
        //    TitleResName = "SA_ChangeThemes",
        //    DescResName = "SA_ChangeThemesDesc",
        //    PermssionSetResName = "SA_Managementbase"
        //)]
        //public ActionResult ChangeTheme(string theme)
        //{
        //    var web = _context.Web;
        //    //WebSite.Open(RouteData);
        //    web.Theme = theme;
        //    _context.DataContext.Webs.Update(web);
        //    _context.DataContext.SaveChanges();

        //    //web.Update();

        //    return Content(HtmlUIExtensions.Theme(theme));
        //}

        //public ActionResult LoadTheme(string theme)
        //{
        //    return Content(HtmlUIExtensions.Theme(theme));
        //}

        [SecurityAction("Management base", "Use Translator", "Allows users can use translator localize the website.",
            TitleResName = "SA_UseTranslator",
            DescResName = "SA_UseTranslatorDesc",
            PermssionSetResName = "SA_Managementbase"
        )]
        [SiteControlPanel(ResKey = "RES_TRANSLATOR", Sequence = 3, Group = "Tools", GroupResKey = "RES_TOOLS", ShowInTopSiteOnly = true)]
        public ActionResult Translator()
        {
            ViewBag.BingID = System.Web.Configuration.WebConfigurationManager.AppSettings["BingAppID"];
            return View();
        }

        [HttpPost]
        public ActionResult Translator(string bingAppID, FormCollection forms)
        {
            if (_context.IsAuthorized(this, "Translator"))
            {
                if (!string.IsNullOrEmpty(bingAppID))
                {
                    DnaConfig.UpdateWebConfig("configuration/appSettings/add[@key='BingAppID']", "value", bingAppID.ToLower());
                }

                if (HttpContext.Request.Files.Count > 0)
                {
                    var root = HttpContext.Server.MapPath("~/App_GlobalResources/");
                    var zip = new ZipExtract(HttpContext.Request.Files[0].InputStream);
                    zip.ExtractTo(root);
                }
                ViewBag.BingID = bingAppID;
                return View();
            }
            else
                return RedirectToAction("AccessDenied", "Security", new { Area = "" });
        }

        public ActionResult LabelEditor(string res, string from, string to)
        {
            if (_context.IsAuthorized(this, "Translator"))
            {
                var _t = string.IsNullOrEmpty(to) ? from : to;
                ViewBag.BaseName = res;
                ViewBag.FromCulture = CultureInfo.GetCultureInfo(from);
                ViewBag.ToCulture = CultureInfo.GetCultureInfo(_t);
                var resFile = GetResXFileName(res, _t);

                if (!System.IO.File.Exists(resFile))
                {
                    var defaultRes = GetResXFileName(res, from);
                    System.IO.File.Copy(defaultRes, resFile);
                }
                return View();
            }
            else
                return RedirectToAction("AccessDenied", "Security", new { Area = "" });
        }

        [Authorize]
        [ValidateInput(false)]
        public bool BatchTranslate(string res, string lan, string dict)
        {
            if (_context.IsAuthorized(this, "Translator"))
            {
                var entries = (new System.Web.Script.Serialization.JavaScriptSerializer()).Deserialize<DictionaryEntry[]>(dict);
                string resxFile = GetResXFileName(res, lan);
                using (var resxWriter = new ResXResourceWriter(resxFile))
                {
                    foreach (var entry in entries)
                        resxWriter.AddResource(entry.Key.ToString(), entry.Value.ToString());
                }
                return true;
            }
            return false;
        }

        [Authorize]
        public ActionResult LoadResXData(string res, string lan)
        {
            var dict = LoadResXEntries(res, lan);
            return Json(dict, JsonRequestBehavior.AllowGet);
        }

        [Authorize]
        [Pagable]
        public ActionResult ResXData(string res, string from, string to, QueryParams query)
        {
            var fromDict = LoadResXEntries(res, from);
            var toDict = LoadResXEntries(res, string.IsNullOrEmpty(to) ? from : to);
            var model = new List<Collation>();

            foreach (var entry in fromDict)
            {
                var _toEntry = toDict.Find(d => d.Key.Equals(entry.Key));
                if (!string.IsNullOrEmpty(_toEntry.Key as string))
                    model.Add(new Collation()
                    {
                        Key = entry.Key.ToString(),
                        Value = entry.Value.ToString(),
                        Label = _toEntry.Value.ToString()
                    });
            }

            var result = model.Skip(query.GetSkipRecordCount(isZeroBase: true)).Take(query.Size);
            return View(new ModelWrapper<Collation>()
            {
                Model = result,
                Total = model.Count()
            });
        }

        private List<DictionaryEntry> LoadResXEntries(string res, string lan)
        {
            var resxFile = GetResXFileName(res, lan);

            var model = new List<DictionaryEntry>();
            using (var resxReader = new ResXResourceReader(resxFile))
            {
                foreach (DictionaryEntry d in resxReader)
                    model.Add(d);
            }
            return model;
        }

        private string GetResXFileName(string res, string lan)
        {
            var resxFile = Server.MapPath("~/App_GlobalResources/" + res + "/" + res + (lan.Equals("en-us", StringComparison.OrdinalIgnoreCase) ? ".resx" : "." + lan + ".resx"));
            return resxFile;
        }

        public void Translate(string res, string lan, string key, string label)
        {
            string resxFile = GetResXFileName(res, lan);
            var entries = LoadResXEntries(res, lan);
            using (var resxWriter = new ResXResourceWriter(resxFile))
            {
                foreach (var entry in entries)
                {
                    var k = entry.Key.ToString();
                    if (k == key)
                        resxWriter.AddResource(key, label);
                    else
                        resxWriter.AddResource(k, entry.Value.ToString());
                }
            }
        }

        //public ActionResult DownloadLanguage(string lang)
        //{
        //    throw new NotImplementedException();

        //    //if (string.IsNullOrEmpty(lang))
        //    //    throw new ArgumentNullException("lang");

        //    //string globalPath = HttpContext.Server.MapPath("~/App_GlobalResources/");
        //    //var dirs = Directory.GetDirectories(globalPath);
        //    //var zip = new ZipCompress() { Path = globalPath };

        //    //foreach (var dir in dirs)
        //    //{
        //    //    var dirInfo = new DirectoryInfo(dir);
        //    //    var file = dir + "\\" + dirInfo.Name + (lang.Equals("en-US", StringComparison.OrdinalIgnoreCase) ? "" : "." + lang) + ".resx";
        //    //    if (System.IO.File.Exists(file))
        //    //        zip.AddFile(file);
        //    //}
        //    ////Installation.PackageDescriptor
        //    //var stream = zip.Compress();
        //    //var downloadName = TextUtility.Slug("DNA-" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString());

        //    //return File(stream, "application/x-zip-compressed", downloadName + "." + lang + ".zip");

        //    //throw new FileNotFoundException();
        //}

    }

    public class Collation
    {
        public string Key { get; set; }
        public string Value { get; set; }
        public string Label { get; set; }
    }
}
